package gtkwire;

import java.util.Vector;
import java.io.*;
import java.util.StringTokenizer;

/* 
Code generator
--------------------
sgen 	-c <command> 
sgen	-cr <command_request> 
sgen	-s <signal>
sgen 	-l for line clean up
sgen	-cl <GtkWidgetName> for class file stubb and GladeWidget line
sgen 	-syn <classfilename> to create raw synopsis of class
*/
public class sgen
{
	private static StringBuffer lines = new StringBuffer();
	private static String outFileName = null;
	private static String[] mods = { "private","public","static","protected", "void" };
	private static String INSET = "                    ";

	public static void main(String[] args) 
	{
		if( args.length < 1 || args.length > 3 )
		{
			System.out.println("args error");
			System.exit( 1 );
		}
		String p1 = args[ 0 ];
		if( args.length == 2 )
		{
			String signal = args[ 1 ].toLowerCase();
			String SIGNAL = args[ 1 ].toUpperCase();
			if( p1.equals( "-c" ) ) createCommandLines( SIGNAL, signal );
			else if( p1.equals( "-cr" ) ) createCommandRequestLines( SIGNAL, signal );
			else if( p1.equals( "-s" ) ) createSignalLines( SIGNAL, signal );
			else if( p1.equals( "-l" ) )
			{
				File inf = new File( System.getProperty("user.dir") + "/" + args[ 1 ] );
				cleanUpLines( inf );
			}
			else if( p1.equals( "-cl" ) ) createClassLines( args );
		}
		if( args.length == 3 )
			if( p1.equals( "-cl" ) ) createClassLines( args );
	}

	private static void add( String s )
	{
		lines.append( s + "\n" );
	}

	public static void createCommandLines( String SIGNAL, String signal )
	{
		String dir = System.getProperty("user.dir");

		//--- autogen GladeWireCommand.java
		File gwFile =  new File( dir + "/GTKWireCommand.java" );
		Vector<String> gwCommandLines = getFileLines(gwFile);
		int fieldsStart = findMacthingLine( "//##commandfields##", gwCommandLines );
		String newField =  "	public static final GTKWireCommand " + SIGNAL +" = new GTKWireCommand( \"" + signal + "\" );\n";
		int insertIndex = findABCPlace( fieldsStart + 1, newField, gwCommandLines );
		gwCommandLines.insertElementAt( newField, insertIndex );
		writeFile( gwFile, gwCommandLines );

		//--- autogen gladewire_command.h, define
		File gwComCFile =  new File( dir + "/jni/gtkwire_command.c" );
		Vector<String> comCLines = getFileLines(gwComCFile);
		int defStart = findMacthingLine( "//##defines##", comCLines );
		String newDef =  "#define " + SIGNAL + " " + "\"" + signal + "\"\n";
		insertIndex = findABCPlace( defStart + 1, newDef, comCLines );
		comCLines.insertElementAt( newDef, insertIndex );
		//--- autogen gladewire_command.h, func def
		int funcStart = findMacthingLine( "//##funcdecs##", comCLines );
		String newFuncDef = "static void " + signal + " (GtkWidget *widget, gint data_type, gpointer data, gpointer data2);\n";
		insertIndex = findABCPlace( funcStart + 1, newFuncDef, comCLines );
		comCLines.insertElementAt( newFuncDef, insertIndex );

		//--- autogen gladewire_command.c, hashline
		int hashStart = findMacthingLine( "//##hashlines##", comCLines );
		String newHash = "	g_hash_table_insert (command_func_table, " + SIGNAL + ", " + signal + ");\n";
		insertIndex = findABCPlace( hashStart + 1, newHash, comCLines );
		comCLines.insertElementAt( newHash, insertIndex );
		//--- autogen gladewire_command.c, method
		int from = findMacthingLine( "//##handlerfuncs##", comCLines );
		String newMethod = signal + " (GtkWidget *widget, gint data_type, gpointer data, gpointer data2)\n";
		String newMethodAll ="\n" + "static void\n" + newMethod + "{\n" + "\n" + "}\n";
		boolean more = true;
		String line;
		while( more )
		{
			line = comCLines.elementAt( from );
			if( line.startsWith("static void") )
			{
				line = comCLines.elementAt( from + 1 );
				if( line.compareTo( newMethod ) >= 0 )
				{
					comCLines.insertElementAt( newMethodAll, from - 1 );
					more = false;
				}
			}

			if( from >= comCLines.size() ) 
			{
				//newMethodAll = "\n" + newMethod;
				comCLines.add( newMethodAll );
				more = false;
			}
			from++;
		}
		writeFile( gwComCFile, comCLines );
	}

	public static void createCommandRequestLines( String SIGNAL, String signal )
	{
		String dir = System.getProperty("user.dir");

		//--- autogen GladeWireCommand.java
		File gwFile =  new File( dir + "/GTKWireCommandRequest.java" );
		Vector<String> gwCommandLines = getFileLines(gwFile);
		int fieldsStart = findMacthingLine( "//##commandrequestfields##", gwCommandLines );
		//String newField =  "	public static final GladeWireCommand " + SIGNAL +" = new GladeWireCommand( \"" + signal + "\" );\n";
		String newField =  "	public static final GTKWireCommandRequest " + SIGNAL +" = new GTKWireCommandRequest( \"" + signal + "\" );\n";
		int insertIndex = findABCPlace( fieldsStart + 1, newField, gwCommandLines );
		gwCommandLines.insertElementAt( newField, insertIndex );
		writeFile( gwFile, gwCommandLines );

		//--- autogen gladewire_command.h, define
		File gwComHFile =  new File( dir + "/jni/gtkwire_command.c" );
		Vector<String> comHLines = getFileLines(gwComHFile);
		int defStart = findMacthingLine( "//##defines##", comHLines );
		String newDef =  "#define " + SIGNAL + " " + "\"" + signal + "\"\n";
		insertIndex = findABCPlace( defStart + 1, newDef, comHLines );
		comHLines.insertElementAt( newDef, insertIndex );
		//--- autogen gladewire_command.h, func def
		int funcStart = findMacthingLine( "//##funcdecs##", comHLines );
		String newFuncDef = "static void " + signal + " (GtkWidget *widget, gint data_type, gpointer data, gpointer data2);\n";
		insertIndex = findABCPlace( funcStart + 1, newFuncDef, comHLines );
		comHLines.insertElementAt( newFuncDef, insertIndex );

		//--- autogen gladewire_command.c, hashline
		int hashStart = findMacthingLine( "//##hashlines##", comHLines );
		String newHash = "	g_hash_table_insert (command_func_table, " + SIGNAL + ", " + signal + " );\n";
		insertIndex = findABCPlace( hashStart + 1, newHash, comHLines );
		comHLines.insertElementAt( newHash, insertIndex );
		//--- autogen gladewire_command.c, method
		int from = findMacthingLine( "//##handlerfuncs##", comHLines );
		String newMethod = signal + " (GtkWidget *widget, gint data_type, gpointer data, gpointer data2)\n";
		String newMethodAll ="\n" + "static void\n" + newMethod + "{\n" + "\n" + "}\n";
		boolean more = true;
		String line;
		while( more )
		{
			line = comHLines.elementAt( from );
			if( line.startsWith("static void") )
			{
				line = comHLines.elementAt( from + 1 );
				if( line.compareTo( newMethod ) >= 0 )
				{
					comHLines.insertElementAt( newMethodAll, from - 1 );
					more = false;
				}
			}

			if( from >= comHLines.size() ) 
			{
				//newMethodAll = "\n" + newMethod;
				comHLines.add( newMethodAll );
				more = false;
			}
			from++;
		}
		writeFile( gwComHFile, comHLines );
	}

	public static void createSignalLines( String SIGNAL, String signal )
	{
		add( "public static final GTKWireSignal " + SIGNAL +" = new GTKWireSignal( \"" + signal + "\" );" );
		add( "" );
		add( "#define " + SIGNAL + " " + "\"" + signal + "\"" );
		add( "");
		add( "static void " + signal + " ( GtkWidget *widget,  gpointer data );" );
		add( "" );
		add( "		g_hash_table_insert( sig_func_table, "+ SIGNAL + ", G_CALLBACK(" + signal + ") );" );
		add( "" );
		add( "static void" );
		add( signal + " ( GtkWidget *widget,  gpointer data )" );
		add( "{" );
		add( "	send_glade_signal (widget, " + SIGNAL + ", M_NO_OBJECT, NULL);" );
		add( "}" );
		outFileName =  System.getProperty("user.dir") + "/gladewire.stubs";
		writeOutFile();
	}
	
	private static void createClassLines( String[] args )
	{
		String c = args[ 1 ];
		String e = "";
		if( args.length == 3 ) e = args[ 2 ];
		add( "public static final String "+ c + " = \"" + c + "\";" );
		add( "" );
		add( "package gladewire.widget;" );
		add( "" );
		add( "public class " + c + " extends " + e );
		add( "{" );
		add( "        public " + c +"( String name )" );
		add( "        {" );
		add( "                 super( name );" );
		add( "                 this.widgetType = GladeWidget."+ c + ";" );
		add( "        }" );
		add( "" );
		add( "}//end class" );
		outFileName = "/gladewire.stubs";
	}

	private static void cleanUpLines( File gwFile )
	{
		System.out.println("wderf");
		Vector<String> gwCommandLines = getFileLines(gwFile);
		StringTokenizer tok;
		String w;
		for( int i = 0; i < gwCommandLines.size(); i++ )
		{
			tok = new StringTokenizer(gwCommandLines.elementAt( i ) );
			w = tok.nextToken();
			lines.append("#define " + w + "_ID " + "   " + w.hashCode() + "\n" );
		}

		outFileName = "/lines.txt";

		File f = new File( System.getProperty("user.dir") + outFileName );
		String res = lines.toString();
		writeFile( f, res );
		System.out.println( res );
	}

	private static int findMacthingLine( String test, Vector<String> doclines )
	{
		for( int i = 0; i < doclines.size(); i++ )
			if( doclines.elementAt( i ).startsWith(test) ) return i;
		
		return -1;
	}

	private static int findABCPlace( int from, String test, Vector<String> doclines )
	{
		boolean more = true;
		String line;
		while( more )
		{
			line =  doclines.elementAt( from );
			if( line.length() < 5 ) return from;
			if( line.compareTo( test ) >= 0 ) return from;
			if( from >= doclines.size() ) more = false;
			from++;
		}
		return -1;
	}

	private static boolean lineIsDocLine( String line )
	{
		StringTokenizer st = new StringTokenizer( line );
		if( !st.hasMoreTokens() ) return false;
		String ft = st.nextToken();
		return isMod( ft );
	}
	
	private static boolean nonVoidModFirst( String line )
	{
		int mods = 0;
		StringTokenizer st = new StringTokenizer( line );
		if( !st.hasMoreTokens() ) return false;
		String ft = st.nextToken();
		return isNonVoidMod( ft );
	}

	private static boolean isMod( String s )
	{
		for( int i = 0; i < mods.length; i++ )
			if( mods[ i ].equals( s ) ) return true;

		return false;
	}

	private static boolean isNonVoidMod( String s )
	{
		for( int i = 0; i < mods.length - 1; i++ ) //void is last
			if( mods[ i ].equals( s ) ) return true;

		return false;
	}
	private static String trim( String line )
	{
		StringBuffer res = new StringBuffer();	
		StringTokenizer st = new StringTokenizer( line );
		while( st.hasMoreTokens() )
		{ 
			res.append( st.nextToken() );
			if( st.hasMoreTokens() ) res.append( " " );
		}
		return res.toString();
	}

	private static String cutBody( String line )
	{
		if( line.indexOf("{") == -1 ) return line;
		return line.substring( 0, line.indexOf("{") );
	}
	
	private static String getContents(File aFile) 
	{
		StringBuilder contents = new StringBuilder();
    		try 
		{
			BufferedReader input =  new BufferedReader(new FileReader(aFile));
			String line = null;
			while (( line = input.readLine()) != null)
			{
				contents.append(line);
				contents.append(System.getProperty("line.separator"));
				
			}
			input.close();
		}
		catch (IOException e )
		{
			e.printStackTrace();
		}
		return contents.toString();
	}

	private static Vector<String> getFileLines(File aFile) 
	{
		Vector<String> contents = new Vector<String>();//very slow
    		try 
		{
			BufferedReader input =  new BufferedReader(new FileReader(aFile));
			String line = null;
			while (( line = input.readLine()) != null)
			{
				contents.add(line + System.getProperty("line.separator") );
			}
			input.close();
		}
		catch (IOException e )
		{
			e.printStackTrace();
		}
		return contents;
	}

	private static void writeOutFile()
	{
		writeFile( new File(outFileName), lines.toString() );
	}

	private static void writeFile( File file, Vector<String> ls )
	{	
		StringBuffer cont = new StringBuffer();
		for( int i = 0; i< ls.size(); i++ )
			cont.append( ls.elementAt( i ) );

		writeFile( file, cont.toString() );
	}	

	private static void writeFile( File file, String cont )
	{
		try {
			file.delete();
			Writer output = new BufferedWriter( new FileWriter( file ) );
			output.write( cont );
			output.close();
		}
		catch( IOException e )
		{
			System.out.println( e.getMessage() );
		}
	}

}//end class
